package com.carhailing.client.service.impl;

import com.bawei.common.security.utils.SecurityUtils;
import com.carhailing.client.mapper.ClientMapper;
import com.carhailing.client.service.ClientService;
import com.carhailing.client.util.BigDecimalUtils;

import com.carhailing.client.config.DelayedQueue;
import com.carhailing.client.util.SnowflakeIdWorker;
import com.carhailing.common.constants.CommonStatusEnum;
import com.carhailing.common.domain.request.PageInfoVo;
import com.carhailing.common.domain.response.*;
import com.carhailing.common.result.PageResult;
import com.carhailing.common.result.Result;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.reflections.Reflections.log;

@Service
public class ClientServiceimpl implements ClientService {
    @Autowired
    private ClientMapper clientMapper;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private DelayedQueue delayedQueue;




    @Override
    public Result InitiateOrder(StartCarOrder startCarOrder) {
        // 使用雪花算法生成唯一、有序的订单号    假设workerId和datacenterId都为0
        SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(0, 0);
        long orderNum = snowflakeIdWorker.nextId();

        //订单编号做key
        RLock lock = redissonClient.getLock("lock"+orderNum);
        boolean locked = false;

        try {
            locked = lock.tryLock(5, TimeUnit.SECONDS);
            if (!locked) {
                return Result.error("获取锁失败");
            }

            //判断是否存在
            StartCarOrder startCarOrders=clientMapper.selectOrderTrade(startCarOrder.getStartCarId());
            if (!StringUtils.isEmpty(startCarOrders)) {
                return Result.error("订单已经存在");
            }


            // 添加订单
            CarOrder CarOrder = new CarOrder();
            // 订单编号
            CarOrder.setOrderNumber(orderNum);
            //登录iD
            CarOrder.setUserId(SecurityUtils.getUserId());
            // 出发地经度
            CarOrder.setDepLongitude(startCarOrder.getDepLongitude());
            CarOrder.setDepLatitude(startCarOrder.getDepLatitude());
            // 出发地址
            CarOrder.setStartAddress(startCarOrder.getStartAddress());
            // 目的地
            CarOrder.setEndAddress(startCarOrder.getEndAddress());
            //目的地经度
            CarOrder.setDestLongitude(startCarOrder.getDestLongitude());
            CarOrder.setDestLatitude(startCarOrder.getDestLatitude());
            // 订单状态
            CarOrder.setOrderStatus(0);
            //预计金额
            CarOrder.setPrice(startCarOrder.getFare());
            //总金额
            CarOrder.setTotalPrice(startCarOrder.getFare());
            //应付金额
            CarOrder.setPayPrice(startCarOrder.getFare());
            //优惠卷id
            CarOrder.setCouponId(startCarOrder.getCouponId());
            //结束时间
            CarOrder.setEndTime(startCarOrder.getEndTime());
            //司机id
            CarOrder.setDriverId(startCarOrder.getDriverId());
            //车辆信息id
            CarOrder.setVehicleId(startCarOrder.getStartCarId());
            //创建时间
            CarOrder.setCreateTime(startCarOrder.getCreateTime());
            // 服务类型
            CarOrder.setServiceTypeTrade(startCarOrder.getServiceTypeTrade());

            clientMapper.addOrderTrade(CarOrder);

            // 添加订单到延迟队列
            delayedQueue.sendDelayedQueue("orderTradeQueue",startCarOrder,5 * 60 * 1000);

            return Result.success(CarOrder, "订单发起成功");
        } catch (InterruptedException e) {
            e.printStackTrace();
            return Result.error("获取锁异常");
        } finally {
            if (lock.isLocked()) {
                    //释放锁
                    lock.unlock();
            }
        }
    }



    @Override
    public Result<PageResult<CarOrder>> OrderList(PageInfoVo pageInfoVo) {
        PageHelper.startPage(pageInfoVo.getPageNum(), pageInfoVo.getPageSize());

        List<CarOrder> orderTradeDtoList = clientMapper.OrderList(pageInfoVo);

        PageInfo<CarOrder> orderTradeDtoPageInfo = new PageInfo<>(orderTradeDtoList);

        return Result.success(PageResult.toPageResult(orderTradeDtoPageInfo.getTotal(),orderTradeDtoList));
    }

    @Override
    public Result DriverTakeOrder(Integer orderTradeId) {
        // 获取订单信息
        CarOrder CarOrder = clientMapper.selectOrderTradeById(orderTradeId);

        // 判断订单是否存在
        if (CarOrder == null) {
            return Result.error("订单不存在");
        }
        // 拿到登录人的id
        Long userId = SecurityUtils.getUserId();
        // 判断用户是否登录
        if (userId == null) {
            return Result.error("用户未登录");
        }
        // 判断订单状态
        if (CarOrder.getOrderStatus() != 0) {
            return Result.error("订单状态异常");
        }
        // 修改订单状态
        CarOrder.setOrderStatus(1);
        clientMapper.updateOrderTrade(CarOrder);
        return Result.success(CarOrder, "接单成功");
    }



    @Override
    public ResponseResult forecastPrice(String depLongitude, String depLatitude, String destLongitude, String destLatitude) {
        log.info("出发地经度："+depLongitude);
        log.info("出发地纬度："+depLatitude);
        log.info("目的地经度："+destLongitude);
        log.info("目的地纬度："+destLatitude);

        log.info("调用地图服务，查询距离和时长");
        ForecastPriceDTO forecastPriceDTO = new ForecastPriceDTO();
        forecastPriceDTO.setDepLongitude(depLongitude);
        forecastPriceDTO.setDepLatitude(depLatitude);
        forecastPriceDTO.setDestLongitude(destLongitude);
        forecastPriceDTO.setDestLatitude(destLatitude);
        ResponseResult<DirectionResponse> direction = clientMapper.direction(forecastPriceDTO);
        Integer distance = direction.getData().getDistance();
        Integer duration = direction.getData().getDuration();
        log.info(("距离："+distance+",时长："+duration));

        log.info("读取计价规则");
        Map<String,Object> queryMap = new HashMap<>();
        queryMap.put("city_code","110000");
        queryMap.put("vehicle_type","1");
        List<PriceRule> priceRules = clientMapper.selectByMap(queryMap);

        if (priceRules.size() == 0){
            return ResponseResult.fail(CommonStatusEnum.PRICE_RULE_EMPTY.getCode(),CommonStatusEnum.VERIFICATION_CODE_ERROR.getValue());
        }

        PriceRule priceRule = priceRules.get(0);
        log.info("计价规则："+priceRule);
        log.info("根据距离、时长和计价规则，计算价格");

        double price = getPrice(distance, duration, priceRule);

        ForecastPriceResponse forecastPriceResponse = new ForecastPriceResponse();
        forecastPriceResponse.setPrice(price);
        return ResponseResult.success(forecastPriceResponse);
    }

    @Override
    public Result reservation(BookingCarOrder BookingCarOrder) {
        // 使用雪花算法生成唯一、有序的订单号    假设workerId和datacenterId都为0
        SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(0, 0);
        long orderNum = snowflakeIdWorker.nextId();

        //订单编号做key
        RLock lock = redissonClient.getLock("lock" + orderNum);

        try {
            boolean tryLock = lock.tryLock(5, TimeUnit.SECONDS);
            if (!tryLock) {
                return Result.error("获取锁失败");
            }

            //判断是否存在
            Integer i = clientMapper.selectBookingCarOrder(BookingCarOrder.getBookingCarOrderId());
            if(i==1){
                return Result.error("订单已经存在");
            }

            //添加订单
            BookingCarOrder BookingCarOrders = new BookingCarOrder();

            BookingCarOrders.setBookingCarOrderId(BookingCarOrder.getBookingCarOrderId());
            BookingCarOrders.setOrderNumber(orderNum);
            BookingCarOrders.setDepLongitude(BookingCarOrder.getDepLongitude());
            BookingCarOrders.setDepLatitude(BookingCarOrder.getDepLatitude());
            BookingCarOrders.setStartAddress(BookingCarOrder.getStartAddress());
            BookingCarOrders.setEndAddress(BookingCarOrder.getEndAddress());
            BookingCarOrders.setDestLongitude(BookingCarOrder.getDestLongitude());
            BookingCarOrders.setDepLatitude(BookingCarOrder.getDestLatitude());
            BookingCarOrders.setOrderStatus(0);
            BookingCarOrders.setFare(BookingCarOrder.getFare());
            BookingCarOrders.setTotalFare(BookingCarOrder.getTotalFare());
            BookingCarOrders.setPayFare(BookingCarOrder.getPayFare());
            BookingCarOrders.setCouponId(BookingCarOrder.getCouponId());
            BookingCarOrders.setEndTime(BookingCarOrder.getEndTime());
            BookingCarOrders.setDriverId(BookingCarOrder.getDriverId());
            BookingCarOrders.setVehicleId(BookingCarOrder.getVehicleId());
            BookingCarOrders.setCreateTime(BookingCarOrder.getCreateTime());

            clientMapper.addbookingarOrder(BookingCarOrders);

            return Result.success(BookingCarOrders,"预约成功");

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            if(lock.isLocked()){
                lock.unlock();
            }
        }

    }

    @Override
    public Result airportPickup(ReceivePlaneOrderDto receivePlaneOrderDto) {

        // 使用雪花算法生成唯一、有序的订单号    假设workerId和datacenterId都为0
        SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(0, 0);
        long orderNum = snowflakeIdWorker.nextId();

        //订单编号做key
        RLock lock = redissonClient.getLock("lock" + orderNum);

        try {
            boolean tryLock = lock.tryLock(5, TimeUnit.SECONDS);

            if(!tryLock){
                return Result.error("获取锁失败");
            }

            ReceivePlaneOrderDto receivePlaneOrderDtos=clientMapper.selectReceivePlaneOrder(receivePlaneOrderDto.getReceivePlaneOrderId());
            if(receivePlaneOrderDtos!=null){
                return Result.error("订单已经存在");
            }

            ReceivePlaneOrderDto receivePlaneOrderDto1 = new ReceivePlaneOrderDto();
            receivePlaneOrderDto1.setReceivePlaneOrderId(receivePlaneOrderDto.getReceivePlaneOrderId());
            receivePlaneOrderDto1.setOrderNumber(orderNum);
            receivePlaneOrderDto1.setDepLongitude(receivePlaneOrderDto.getDepLongitude());
            receivePlaneOrderDto1.setDepLatitude(receivePlaneOrderDto.getDepLatitude());
            receivePlaneOrderDto1.setStartAddress(receivePlaneOrderDto.getStartAddress());
            receivePlaneOrderDto1.setEndAddress(receivePlaneOrderDto.getEndAddress());
            receivePlaneOrderDto1.setDestLongitude(receivePlaneOrderDto.getDestLongitude());
            receivePlaneOrderDto1.setDestLatitude(receivePlaneOrderDto.getDestLatitude());
            receivePlaneOrderDto1.setOrderStatus(0);
            receivePlaneOrderDto1.setFare(receivePlaneOrderDto.getFare());
            receivePlaneOrderDto1.setTotalFare(receivePlaneOrderDto.getTotalFare());
            receivePlaneOrderDto1.setPayFare(receivePlaneOrderDto.getPayFare());
            receivePlaneOrderDto1.setCouponId(receivePlaneOrderDto.getCouponId());
            receivePlaneOrderDto1.setEndTime(receivePlaneOrderDto.getEndTime());
            receivePlaneOrderDto1.setDriverId(receivePlaneOrderDto.getDriverId());
            receivePlaneOrderDto1.setVehicleId(receivePlaneOrderDto.getVehicleId());
            receivePlaneOrderDto1.setCreateTime(receivePlaneOrderDto.getCreateTime());
            clientMapper.addReceivePlaneOrder(receivePlaneOrderDto1);

            return Result.success(receivePlaneOrderDto1,"接机单下单成功");

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            if(lock.isLocked()){
                lock.unlock();
            }
        }
    }

    @Override
    public void delCarOrder(Long startCarId) {
        clientMapper.delCarOrder(startCarId);
    }


    /**
     * 根据距离、时长 和计价规则，计算最终价格
     * @param distance  距离
     * @param duration  时长
     * @param priceRule 计价规则
     * @return
     */
    private double getPrice(Integer distance , Integer duration,PriceRule priceRule){
        double price = 0;

        // 起步价
        Double startFare = priceRule.getStartFare();
        log.info("起步价："+startFare);
        price = BigDecimalUtils.add(price,startFare);

        // 里程费
        // 总里程 km
        double distanceMile = BigDecimalUtils.divide(distance,1000);
        log.info("总里程："+distanceMile+"km");
        // 起步里程
        double startMile = (double)priceRule.getStartMile();
        log.info("起步里程："+startMile+"km");
        //超过起步里程数
        double distanceSubtract = BigDecimalUtils.substract(distanceMile,startMile);
        log.info("超过起步里程数："+distanceSubtract+"km");
        // 最终收费的里程数 km
        double mile = distanceSubtract<0?0:distanceSubtract;
        log.info("最终收费的里程数："+mile+"km");
        // 计程单价 元/km
        double unitPricePerMile = priceRule.getUnitPricePerMile();
        log.info("计程单价："+unitPricePerMile+"元/km");
        // 里程价格
        double mileFare = BigDecimalUtils.multiply(mile,unitPricePerMile);
        log.info("里程价格："+mileFare+"元");
        price = BigDecimalUtils.add(price,mileFare);

        // 时长费
        // 时长的分钟数
        double timeMinute = BigDecimalUtils.divide(duration,60);
        log.info("时长的分钟数："+timeMinute+"分钟");
        // 计时单价
        double unitPricePerMinute = priceRule.getUnitPricePerMinute();
        log.info("计时单价："+unitPricePerMinute+"元");
        // 时长费用
        double timeFare = BigDecimalUtils.multiply(timeMinute,unitPricePerMinute);
        log.info("时长费用："+timeFare+"元");
        price = BigDecimalUtils.add(price,timeFare);

        BigDecimal priceBigDecimal = new BigDecimal(price);
        priceBigDecimal = priceBigDecimal.setScale(2,BigDecimal.ROUND_HALF_UP);
        log.info("最终费用："+priceBigDecimal.doubleValue()+"元");
        return priceBigDecimal.doubleValue();
    }


}
